#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <functional>
#include "thread.hpp"
#include "LockGuard.hpp"
static const int defaultnum = 5;

class ThreadData
{
public:
    ThreadData(const std::string &name)
        : _threadname(name)
    {
    }
    ~ThreadData()
    {
    }
    std::string threadname() const
    {
        return _threadname;
    }

private:
    std::string _threadname;
};

template <class T>
class Threadpool
{
private: // 单例模式，私有化构造
    Threadpool(int threadnum = defaultnum)
        : _threadnum(threadnum)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _threadnum; i++)
        {
            std::string threadname = "thread-";
            threadname += std::to_string(i+1);
            ThreadData td(threadname);
            _threads.emplace_back(threadname, std::bind(&Threadpool<T>::ThreadRun, this, std::placeholders::_1), td);
            std::cout << threadname.c_str() << "is be created...\n";
        }
    }
    Threadpool(const Threadpool<T> &tp) = delete;
    const Threadpool<T> &operator=(const Threadpool<T>) = delete;
public:
    static Threadpool<T> *GetInstance()
    {
        if (instance == nullptr)   //双层检查，避免竞争锁再检查
        {
            LockGuard lockguard(&sig_lock);
            if (instance == nullptr)
            {
                std::cout << "创建单例成功\n";
                instance = new Threadpool<T>();
            }
        }
        return instance;
    }
    bool Start()
    {
        for (auto &thread : _threads)
        {
            thread.Start();
            std::cout << thread.ThreadName().c_str() << " is running ...\n";
        }
        return true;
    }
    void ThreadWait(const ThreadData &td)
    {
        std::cout << td.threadname().c_str() << " no task sleeping...\n";
        pthread_cond_wait(&_cond, &_mutex);
    }
    void ThreadWake()
    {
        pthread_cond_signal(&_cond);
    }

    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            T t;
            {
                LockGuard lockguard(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                    std::cout << td.threadname().c_str() << "is weakup\n";
                }
                t = _q.front();
                _q.pop();
            }//取完任务就可以解锁了
            t();
            printf("%s handler task %s done, result is : %s\n",
                   td.threadname().c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
        }
    }

    void Push(T&in)
    {
        printf( "other thread push a task, task is : %s\n", in.PrintTask().c_str());
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWake();
    }

    void Join()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }
     ~Threadpool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    std::queue<T> _q;
    std::vector<Thread<ThreadData>> _threads;
    pthread_cond_t _cond;
    pthread_mutex_t _mutex;
    int _threadnum;
    static Threadpool<T> *instance;
    static pthread_mutex_t sig_lock;
};


template<class T>
Threadpool<T>* Threadpool<T>::instance=nullptr;
template<class T>
pthread_mutex_t Threadpool<T>::sig_lock=PTHREAD_MUTEX_INITIALIZER;